/*
 * Copyright (c) Family. All Rights Reserved
 */

package com.driving.exam.spider;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.driving.exam.entity.Coach;
import com.driving.exam.entity.School;
import com.driving.exam.service.ICoachService;
import com.driving.exam.service.ISchoolService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.guet.base.spider.Constants;
import cn.guet.base.spider.http.HttpClientUtil;
import lombok.RequiredArgsConstructor;

/**
 * 教练爬取
 *
 * @author SAGITTAR
 */
@RequiredArgsConstructor
@Component(value = "coachSpider")
public class CoachSpider {

    private static final Logger LOGGER = LogManager.getLogger(CoachSpider.class);

    private static final String COACH_ROOT_PAGE = "http://www.jiakaobaodian.com";

    private final ICoachService coachService;

    private final ISchoolService schoolService;

    public void execute() throws Exception {
        QueryWrapper<Coach> existWrapper = new QueryWrapper<>();
        List<String> bigAreaList = coachService.list(existWrapper).stream().map(Coach::getBigArea)
            .collect(Collectors.toList());
        String webPage = HttpClientUtil.getWebPage(COACH_ROOT_PAGE + "/coach/");
        List<String> provinceUrlList = Jsoup.parse(webPage).select(".list-w").select("a").stream()
            .map(a -> a.attr("href")).collect(Collectors.toList());
        for (String provinceUrl : provinceUrlList) {
            String provincePage = HttpClientUtil.getWebPage(COACH_ROOT_PAGE + provinceUrl);
            Document provinceDocument = Jsoup.parse(provincePage);
            // 省份名称或直辖市名称
            String provinceTitle = provinceDocument.select(".common-channel-crumb").select("a").last().ownText();
            String provinceName = provinceTitle.substring(0, provinceTitle.indexOf("教练"));
            if (bigAreaList.contains(provinceName)) {
                continue;
            }
            Elements cityOrDistrictList;
            // 判断是否直辖市
            if (isDirectCity(provinceUrl)) {
                // 构造直辖市节点
                cityOrDistrictList = new Elements(new Element("a").attr("href", provinceUrl).text(provinceName));
            } else {
                cityOrDistrictList = provinceDocument.select(".list-w").select("a");
            }
            // 遍历城市或行政区
            for (Element cityOrDistrict : cityOrDistrictList) {
                String pageUrl = COACH_ROOT_PAGE + cityOrDistrict.attr("href") + "%sc.html";
                // 遍历页码，第一页开始
                for (int page = 1;; page++) {
                    Document currentPage;
                    try {
                        currentPage = Jsoup.parse(HttpClientUtil.getWebPage(String.format(pageUrl, page)));
                    } catch (IOException exception) {
                        if (exception.getLocalizedMessage().contains(String.valueOf(HttpStatus.SC_NOT_FOUND))) {
                            break;
                        }
                        continue;
                    }
                    if (Objects.isNull(currentPage)) {
                        continue;
                    }

                    ObjectMapper objectMapper = new ObjectMapper();
                    List<Coach> coachPageList = new ArrayList<>(10);
                    for (Element coachEle : currentPage.select("a.img-w")) {
                        Coach theCoach = new Coach();
                        theCoach.setBigArea(provinceName);
                        theCoach.setSmallArea(cityOrDistrict.ownText());
                        String coachUrl = COACH_ROOT_PAGE + coachEle.attr("href");
                        theCoach.setCoachUrl(coachUrl);
                        try {
                            Document coachDoc = Jsoup.parse(HttpClientUtil.getWebPage(coachUrl));
                            theCoach.setName(coachDoc.select("span.title").first().ownText());
                            String price = coachDoc.select("p.price").first().ownText();
                            String priceTag = "￥";
                            if (StringUtils.contains(price, priceTag)) {
                                price = StringUtils.substringAfter(price, priceTag);
                            }
                            theCoach.setPrice(StringUtils.trim(price));
                            Elements telephone = coachDoc.select("p.phone-w");
                            if (Objects.nonNull(telephone)) {
                                // 电话
                                Element span = telephone.select("span").first();
                                if (Objects.nonNull(span)) {
                                    theCoach.setMobile(StringUtils.trim(span.ownText().substring(5)));
                                }
                                // 所属驾校
                                Element school = telephone.select("a").first();
                                if (Objects.nonNull(school)) {
                                    theCoach.setSchoolName(COACH_ROOT_PAGE + school.attr("href").trim());
                                }
                            }

                            Element detail = coachDoc.select(".com-jiaxiao-introducea").select(".content").first();
                            theCoach.setDetail(StringUtils.trim(detail.html()));
                            Element coverEle = coachDoc.select("div.img-w").select("img").first();
                            if (Objects.nonNull(coverEle)) {
                                theCoach.setImagePath(coverEle.attr("src"));
                            }
                            // 教龄
                            Element schoolAge = coachDoc.select("span.qianyue").first();
                            if (Objects.nonNull(schoolAge)) {
                                String age = StringUtils.substringBefore(schoolAge.ownText(), "年").trim();
                                theCoach.setSchoolAge(Integer.parseInt(age));
                            }
                        } catch (Exception e) {
                            LOGGER.error(e.getLocalizedMessage(), e);
                        }
                        coachPageList.add(theCoach);
                    }
                    // 所属驾校
                    List<String> schoolUrl = coachPageList.stream().map(Coach::getSchoolName)
                        .collect(Collectors.toList());
                    QueryWrapper<School> schoolWrapper = new QueryWrapper<>();
                    schoolWrapper.in("school_url", schoolUrl);
                    List<School> schoolList = schoolService.list(schoolWrapper);
                    coachPageList.forEach(coach -> {
                        Optional<School> id = schoolList.stream()
                            .filter(s -> s.getSchoolUrl().equals(coach.getSchoolName())).findFirst();
                        id.ifPresent(school -> coach.setSchoolId(school.getId()));
                    });
                    if (!coachPageList.isEmpty()) {
                        try {
                            coachService.saveBatch(coachPageList);
                        } catch (Exception e) {
                            LOGGER.error(e.getLocalizedMessage(), e);
                        }
                    }
                    String logInfo = provinceName + "-" + cityOrDistrict.ownText() + "-" + page + "-{}";
                    coachPageList.forEach(school -> {
                        try {
                            LOGGER.info(logInfo, objectMapper.writeValueAsString(school));
                        } catch (JsonProcessingException e) {
                            LOGGER.error(e.getLocalizedMessage());
                        }
                    });
                }
                Thread.sleep(Constants.TIME_INTERVAL);
            }
        }
    }

    private static boolean isDirectCity(String url) {
        for (String city : Arrays.asList("beijing", "shanghai", "tianjin", "chongqing")) {
            if (url.contains(city)) {
                return true;
            }
        }
        return false;
    }
}
